/***********************
作用：练习宏定义
Author:LysLee
用法：gcc -E <__FILE__>
说明：默认会迭代替换，直到无法匹匹配宏定义
但当替换后遇到该分支已替换过的宏则不再替换
当宏作为其它宏的参数时，参数宏也会被替换，除非定义宏时对参数使用了#/##
***********************/

#define A B C
#define B C D
#define C B D
#define D E
A

#define quot(x) # x //在参前加#表示参数代入后要用双引号括起来                    
                    //并且实参中的连续多个空白字符被替换成一个空
#define a b
#define mystrcat(c,d) c ## d //两个参数用##连接时，替换时把两个参数直接拼接在一起
//mystrcat(quot(a),quot(b)) #这里预处理器会报错（认为程序员误以为quto被看做宏）
quot(a 		b) //这里a不会被替换
mystrcat(a,quotX(x)) //这里的a也不会被替换

//函数式宏要用\屏蔽换行,使用do-while(0)防止意外闭合if
#define fuc_macro(a,b) do{\
  AA=a+b;\
  BB=a-b;\
}while(0)
if(10>1) fuc_macro(1,2); 
else fuc_macro(3,4);


//C标准内置宏定义
__LINE__　　//当前源程序的行号
__FILE__　　//正在编译的程序的文件名
__DATE__　　//编译的日期字符串，形如"Mmm dd yyyy"
__TIME__　　//编译的时间字符串，形如"hh:mm:ss"
__STDC__　　//如果__STDC__的内容是十进制常数1，则表示编译程序的实现符合标准C


#define STR(s) #s
//#会把原始字符中的"和\替换为\"和\\##(必须有#否则反斜杠会影响下一行) 
fputs(STR(strncmp("ab\"c\0d", "abc'")
      == 0) STR(: @\n), s);


STR(H 			D)

/***************nothing***
HASH_HASH
#define HASH_HASH # ## #
HASH_HASH
****************/
//宏定义可定义无参函数，但要保证调用形式一致
#define FOO() foo
FOO()
// FOO(x):NO Args!

//动参宏定义
#define FOO2(a,...) a ## __VA_ARGS__
FOO2(1, 2, 3,4)

//宏定义对参数作#或者##操作则参数不展开否则先展开参数
#define sh(x) printf("n" #x "=%d, or %d\n",n##x,alt[x])
#define sub_z 26
sh(sub_z)

//替换后和其他部分组合成的内容如果匹配分支链中替换过的宏也不能再替换
#define x 3
#define f(a) f(x * (a))
#undef x
#define x 2
#define g f
#define t(a) a
t(t(g)(0) + t)(1);  //最后的t(1) 不再替换


#define FOO_ 0
#define FOO_1 1
#define PRIMITIVE_CAT(x, y) x ## y
#define CAT(x, y) PRIMITIVE_CAT(x, y)

CAT(FOO_, 1)

#define EXPAND_IF_PAREN(x) EAT x
#define EAT(x)

EXPAND_IF_PAREN((12))
EXPAND_IF_PAREN(12)

#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define IF_TRUE() printf("In true branch");
#define IF_FALSE() printf("In false branch");


#ifndef COND 
    #define COND 1
#endif

IIF( COND ) ( \
    IF_TRUE(), /*comma needed*/ \
    IF_FALSE() \
)

#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0

COMPL(COND)

#define GET_SEC(x, n, ...) n
#define CHECK(...) GET_SEC(__VA_ARGS__, 0)
#define PROBE(x) x, 1


CHECK(PROBE())


#define IS_EMPTY(x) CHECK(CAT(PRIMITIVE_CAT(IS_EMPTY_, x), 0))
#define IS_EMPTY_0 PROBE()
#define EMPTY

IS_EMPTY()
IS_EMPTY(EMPTY)
IS_EMPTY(xxx)

#define IS_PAREN(x) CHECK(IS_PAREN_PROBE x)
#define IS_PAREN_PROBE(...) PROBE()

IS_PAREN(())
IS_PAREN((a, b))
IS_PAREN(xxx)

#define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x))
#define NOT_0 PROBE(~)

NOT(xxx)
NOT(0)

#define BOOL(x) COMPL(NOT(x))
#define IF(c) IIF(BOOL(c))

IF(1)(IF_TRUE(), IF_FALSE())
IF(0)(IF_TRUE(), IF_FALSE())
IF(xxx)(TURE, FALSE)
